/*
 * dht11.c
 *
 *  Created on: Jul 10, 2021
 *      Author: 86181
 */
#include "tim.h"
#include "gpio.h"
#include "main.h"

#define DHT11_In_init()	   	\
{	\
		GPIO_InitTypeDef GPIO_InitStruct = {0}; \
		GPIO_InitStruct.Pin = W1Dat_Pin; \
		GPIO_InitStruct.Mode = GPIO_MODE_INPUT; \
		GPIO_InitStruct.Pull = GPIO_PULLUP; \
		GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; \
		HAL_GPIO_Init(W1Dat_GPIO_Port, &GPIO_InitStruct); \
}

#define DHT11_Out_init()	   	\
{	\
		GPIO_InitTypeDef GPIO_InitStruct = {0}; \
		GPIO_InitStruct.Pin = W1Dat_Pin; \
		GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; \
		GPIO_InitStruct.Pull = GPIO_NOPULL; \
		GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; \
		HAL_GPIO_Init(W1Dat_GPIO_Port, &GPIO_InitStruct); \
}


#define DHT11_DQ_OUT(N) HAL_GPIO_WritePin(W1Dat_GPIO_Port,  \
W1Dat_Pin, N==1?GPIO_PIN_SET:GPIO_PIN_RESET)
#define DHT11_DQ_IN() 	HAL_GPIO_ReadPin(W1Dat_GPIO_Port,  W1Dat_Pin)


/* 主机发送起始信号 */
static void DHT11_StartSignal(void)
{
	DHT11_Out_init();

	/* 主机拉低 >= 18ms */
	DHT11_DQ_OUT(0);
	HAL_Delay(20);

	/* 主机拉高 >= 20~40us */
	DHT11_DQ_OUT(1);
	delay_us(30);

	DHT11_In_init();
}

uint8_t DHT11_RespondSignal(void)
{
	uint8_t retry = 0;

	/* 总线变为低电平说明从设备发送了响应信号: 80us */
	while( DHT11_DQ_IN() && retry <100)
	{
			retry++;
			delay_us(1);
	}

	/* 超时没有收到响应信号 */
	if(retry >= 100)
			return 1;

	/* 从设备再把总线拉高表示从设备要发送数据了: 80us */
	retry =	0;
	while( !DHT11_DQ_IN() && retry <100)
	{
			retry++;
			delay_us(1);
	}

	/* 超时没有收到数据开始信号 */
	if(retry >= 100)
			return 1;

	return 0;
}

uint8_t DHT11_ReadBit(void)   //读取一个位
{
	uint8_t retry = 0;

	/* 从设备回复的每个位数据以低电平标置开始: 50us */
	while( DHT11_DQ_IN() && retry<100 )
	{
			retry++;
			delay_us(1);
	}

	/* 数据位都用高电平表示, 但高电平的长短决定了数据是 1 or 0 */
	retry = 0;
	while( !DHT11_DQ_IN() && retry<100 )
	{
			retry++;
			delay_us(1);
	}

	/* 判断数据位是 1(70us) or 0(26~28us)*/
	delay_us(40);
	if( DHT11_DQ_IN() )
			return 1;
	else
			return 0;
}

uint8_t DHT11_ReadByte(void)    //读取一个字节返回值位采集值
{
	uint8_t     i,dat;

	dat = 0;
	for(i=0; i<8; i++)
	{
		  dat <<= 1;
		  dat |= DHT11_ReadBit();	 //每读取到一个位放到最后一位
	}

	return dat;
}

int DHT11_SampleData(float *temperature, float *humidity)
{
	uint8_t         humi_H8bit;
	uint8_t         humi_L8bit;
	uint8_t         temp_H8bit;
	uint8_t         temp_L8bit;
	uint8_t         check_sum;

	if( !temperature || !humidity )
			return -1;

	/* 主机发起起始信号并等到从设备的响应信号 */
	DHT11_StartSignal();
	if( 0 != DHT11_RespondSignal() )
			return -2;

	humi_H8bit = DHT11_ReadByte();
	humi_L8bit = DHT11_ReadByte();
	temp_H8bit = DHT11_ReadByte();
	temp_L8bit = DHT11_ReadByte();
	check_sum = DHT11_ReadByte();

	if( (humi_H8bit+humi_L8bit+temp_H8bit+temp_L8bit) != check_sum )
	 	return -3;

	*humidity = (humi_H8bit*100 + humi_L8bit) / 100.00;
	*temperature = (temp_H8bit*100 + temp_L8bit) / 100.00;

	return 0;
}

